package cn.com.nes.common.wx;

import cn.com.nes.common.util.Globals;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.util.IOUtil;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import com.wechat.pay.java.service.payments.nativepay.model.QueryOrderByOutTradeNoRequest;
import org.apache.commons.io.IOUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class WechatNativePay {
    /**
     * 商户号
     */
    public static String merchantId = Globals.WECHAT_PAY_MCHID;

    public static String appid = Globals.WECHAT_PAY_APPID;
    /**
     * 商户API私钥路径
     */
    public static String privateKeyPath = "/wechat/cert/apiclient_key.pem";
    /**
     * 商户证书序列号
     */
    public static String merchantSerialNumber = "7DA5EADD341603BA0B5A3DF1ADEC26D31F216889";
    /**
     * 商户APIV3密钥
     */
    public static String apiV3key = "N0CBI2bPED1P4XBR5NJO6NM3OY8KTr9L";

    private final RSAAutoCertificateConfig config;

    // 线程安全的单例
    private static volatile WechatNativePay instance = null;

    public static WechatNativePay getInstance() {
        if (instance == null) {
            synchronized (WechatNativePay.class) {
                if (instance == null) {
                    instance = new WechatNativePay();
                }
            }
        }
        return instance;
    }

    private WechatNativePay() {
        // 读取resource中的证书文件
        Resource resource = new ClassPathResource(privateKeyPath);
        String privateKeyContent = null;
        try {
            privateKeyContent = IOUtil.toString(resource.getInputStream());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 使用自动更新平台证书的RSA配置
        // 一个商户号只能初始化一个配置，否则会因为重复的下载任务报错
        this.config =
                new RSAAutoCertificateConfig.Builder()
                        .merchantId(merchantId)
                        .privateKey(privateKeyContent)
                        .merchantSerialNumber(merchantSerialNumber)
                        .apiV3Key(apiV3key)
                        .build();
    }

    public Map<String, Object> generatePaymentQRCode(int total, String description, String orderNo) {
        NativePayService service = new NativePayService.Builder().config(config).build();
        // request.setXxx(val)设置所需参数，具体参数可见Request定义!
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        amount.setTotal(total);
        request.setAmount(amount);
        // 绑定和美乡村的公众号
        request.setAppid(appid);
        request.setMchid(merchantId);
        request.setDescription(description);
        // 回调地址
        String notifyUrl = "https://ssl.nes.com.cn:8866/AgentPlatform/dtu/wechatPayNotify";
        request.setNotifyUrl(notifyUrl);
        request.setOutTradeNo(orderNo);
        // 5分钟订单过期
        final LocalDateTime createTime = LocalDateTime.now();
        final LocalDateTime expireTime = createTime.plusMinutes(5);
        request.setTimeExpire(expireTime.atOffset(ZoneOffset.ofHours(8)).format(DateTimeFormatter.ISO_DATE_TIME));
        // 调用下单方法，得到应答
        PrepayResponse response = service.prepay(request);
        // 使用微信扫描 code_url 对应的二维码，即可体验Native支付
        Map<String, Object> map = new HashMap<>(3);
        map.put("codeUrl", response.getCodeUrl());
        map.put("createTime", createTime);
        map.put("expireTime", expireTime);
        return map;
    }

    public Transaction parseNotify(HttpServletRequest request) throws IOException {
        // 从请求中获取参数
        String wechatPayCertificateSerialNumber = request.getHeader("Wechatpay-Serial");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String signature = request.getHeader("Wechatpay-Signature");
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String requestBody = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPayCertificateSerialNumber)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();

        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);

        // 以支付通知回调为例，验签、解密并转换成 Transaction
        return parser.parse(requestParam, Transaction.class);
    }

    public Transaction queryPaymentStatus(String orderNo) {
        // 构建service
        NativePayService service = new NativePayService.Builder().config(config).build();
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(merchantId);
        queryRequest.setOutTradeNo(orderNo);
        try {
            return service.queryOrderByOutTradeNo(queryRequest);
        } catch (ServiceException e) {
            // API返回失败, 例如ORDER_NOT_EXISTS
            System.out.printf("code=[%s], message=[%s]\n", e.getErrorCode(), e.getErrorMessage());
            System.out.printf("reponse body=[%s]\n", e.getResponseBody());
            return null;
        }
    }
}
